#region Using Statements
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Runtime.Remoting;
using System.Windows.Forms;
using OhioState.AssetManaged;
using OhioState.Controls;
using OhioState.Controls.GLSL;
using OhioState.Graphics;
using OhioState.Graphics.OpenGL;
using OhioState.Graphics.Proxy;
using OhioState.Math;
#endregion

namespace OhioStateVolumeRenderer
{
    public partial class OSUVolume : Form
    {
        #region Member Variables
        private delegate void addDrawableRowDelegate(IAssetManaged obj);
        private delegate void addMaterialItemDelegate(string name, IAssetManaged material);

        private OpenGLPanel glPanel;
        private ExaminerMouseHandler examiner1;
        private ICamera mainCamera;
        private CameraSelector cameraSwitch;
        private OhioState.Graphics.OpenGL.ViewHandler realView;
        private ViewProxy view;
        private float _viewAngle = 5.0f;
        private float _aspect = 1.0f;
        private float _near = 0.1f;
        private float _far = 100.0f;
        private OhioStateVolumeRenderer.Properties.Settings frmSettings;

        private List<IAssetManaged> _materialList;
        private static string ShaderDir = "Shaders";
        //private static string MaterialDir = "Materials";
        private static string AppUserDir;
        private static string AppMachineDir;
        private static string AppExeDir;
        //testing
        private PlaneMouseHandler planeMouseHandler;
        #endregion Member Variables

        #region Contructors and Initialization
        public OSUVolume()
        {
            //
            //
            // Going to rework this to be more streamlined and meaningful.
            // At some point in time it should be data driven, but right now 
            // it is just an example on how to use the various libraries.
            //
            InitializeComponent();
            frmSettings = OhioStateVolumeRenderer.Properties.Settings.Default;
            AppSettingsReader appSettingReader = new AppSettingsReader();
            //
            // Initial an controls listening to the Asset Manager.
            //
            //InitializeControls();
            //
            // Create initial assets and add them to the asset manager.
            //
            CreateInitialAssets();
            layersControl.SetViewProxy(view);
            //
            // Create the Rendering panel and corresponding view
            //
            CreateRenderServer(viewPanel); // Places the OpenGL window in viewPanel
            //CreateRenderServer(null); // creates a new Window (Form)
            view.Viewport = new Viewport(new Vector2i(0, 0), new Vector2i(glPanel.Width, glPanel.Height));
            //
            // Initialize any shaders brought in as assets.
            //
            InitializeShaders(appSettingReader, glPanel);

            //
            // Set up event to invalidate the form
            //
            // TODO - Why are these here!? This makes no sense!!!
            //
            //shapeControl1.ChangedEvent += new IAssetManagedHandler(invalidateEvent);
            //transferFunctionManager.ChangedEvent += new IAssetManagedHandler(invalidateEvent);
            //materialEditorCtrl1.ChangedEvent += new IAssetManagedHandler(invalidateEvent);

            //shapeControl1.ChangedEvent += new IAssetManagedHandler(RemoteEventHandler.Instance.Invalidate);
            //transferFunctionManager.ChangedEvent += new IAssetManagedHandler(RemoteEventHandler.Instance.Invalidate);
            //materialEditorCtrl1.ChangedEvent += new IAssetManagedHandler(RemoteEventHandler.Instance.Invalidate);
            //AssetManager.Instance.AddItemEvent += new IAssetManagedHandler(RemoteEventHandler.Instance.Invalidate);

            //
            // Create the mouse controllers
            //
            CreateControllers(mainCamera);
            //
            // Initialize controls listening to the Asset Manager.
            //
            InitializeControls();
            //
            // Set-up the remoting framework.
            //
            InitializeRemoting();
        }

        private void CreateInitialAssets()
        {
            CreateCameraSwitcher();
            AddView();
            LoadAssets();
        }

        private void CreateCameraSwitcher()
        {
            //ICamera cam = CreateCamera("MainCamera");
            //cameraSwitch = new CameraSelector("Junk", cam);
            //mainCamera = cam;
            ICamera cam = CreateCamera("PerspectiveView");
            cameraSwitch = new CameraSelector("MainCamera", cam);
            mainCamera = cameraSwitch;
            AssetManager.Instance.Add(cameraSwitch);
            AssetManager.Instance.AssetAdded += new IAssetManagedHandler(AddCameraItemEvent);
        }

        private void AddView()
        {
            //
            // Create a View and assign it to the glPanel.
            // TODO: we need to rewrite glPanel to use Views (or not have cameras, etc.)
            //
            view = new ViewProxy("Main View");
            view.Viewport.AspectFixed = false;
            view.AddChangedEventHandler(new IAssetManagedHandler(invalidateEvent));
            //_view.AddChangedEventHandler(new IAssetManagedHandler(RemoteEventHandler.Instance.Invalidate));
            //debug
            //_view.AddChangedEventHandler(new IAssetManagedHandler(CaptureScreen));
            //debug
            AssetManager.Instance.Add(view);
            
        }

        private ICamera CreateCamera(string name)
        {
            Camera newCamera = new Camera(_viewAngle, _aspect, _near, _far);
            newCamera.SetName(name);
            newCamera.RotationCenter = new Vector3(0.0f, 0.0f, -34.5f);
            newCamera.Translate(-0.5f, -0.5f, -35.0f);
            AssetManager.Instance.Add(newCamera);
            return newCamera;
        }

        private void LoadAssets()
        {
            AppUserDir = Application.UserAppDataPath;
            AppExeDir = Environment.CurrentDirectory + "\\..\\";
            AppMachineDir = Application.CommonAppDataPath;
            LoadShaders();
            LoadLights();
            LoadMaterials();
            //LoadShapes();
        }

        private void LoadShaders()
        {
            //
            // Search the Application settings directory of the current user.
            //
            string searchDir = AppUserDir + "\\" + ShaderDir;
            LoadShaders(searchDir);
            //
            // Search the installation directory.
            //
            searchDir = AppExeDir + "\\" + ShaderDir + "\\";
            LoadShaders(searchDir);
            //
            // Search the application settings directory common for all users of this machine.
            //
            searchDir = AppMachineDir + "\\" + ShaderDir;
            LoadShaders(searchDir);
            //
            // Link a few key shaders and add them to the AssetManager
            //
            //GLShader.Instance.Link(ShaderProgram.SolidColor);
            AssetManager.Instance.Add(ShaderProgram.SolidColor);
            FragmentShader frag = AssetManager.Instance.Find(typeof(FragmentShader), "SolidColor") as FragmentShader;
            VertexShader vert = AssetManager.Instance.Find(typeof(VertexShader), "SolidColor") as VertexShader;
            ShaderProgram solid = new ShaderProgram("SolidColor", vert, frag);
            //glPanel.Link(solid);
            AssetManager.Instance.Add(solid);

            frag = AssetManager.Instance.Find(typeof(FragmentShader), "ModulateTexture") as FragmentShader;
            vert = AssetManager.Instance.Find(typeof(VertexShader), "VertexWithTexture") as VertexShader;
            solid = new ShaderProgram("ModulateTexture", vert, frag);
            //glPanel.Link(solid);
            AssetManager.Instance.Add(solid);

            List<FragmentShader> fragList = new List<FragmentShader>(7);
            List<VertexShader> vertList = new List<VertexShader>(1);
            vertList.Add(vert);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "VolumeShaderTemplate") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "DataInterpolation") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "GradientNull") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "LightIntensityNull") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "PostClassification1D") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "StrengthVolumeNull") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "VolumeShaderBasicInterpolation") as FragmentShader;
            fragList.Add(frag);
            solid = new ShaderProgram("DVR-PostClass", vertList, fragList);
            //glPanel.Link(solid);
            AssetManager.Instance.Add(solid);

            //DVR with 2D transfer function
            fragList = new List<FragmentShader>(7);
            vertList = new List<VertexShader>(1);
            vert = AssetManager.Instance.Find(typeof(VertexShader), "VertexWithTexture") as VertexShader;
            vertList.Add(vert);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "VolumeShaderTemplate") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "DataInterpolation") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "GradientForwardDifferencesNorm") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "LightIntensityNull") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "PostClassification2D") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "StrengthVolumeNull") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "VolumeShaderBasicInterpolation") as FragmentShader;
            fragList.Add(frag);
            ShaderProgram dvr_2DTF = new ShaderProgram("DVR-2D-TransferFunction", vertList, fragList);
            //glPanel.Link(dvr_2DTF);
            AssetManager.Instance.Add(dvr_2DTF);

            //DVR with basic lighting
            fragList = new List<FragmentShader>(7);
            vertList = new List<VertexShader>(1);
            vert = AssetManager.Instance.Find(typeof(VertexShader), "VertexWithTexture") as VertexShader;
            vertList.Add(vert);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "VolumeShaderTemplate") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "DataInterpolation") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "GradientForwardDifferences") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "LightIntensityDiffuseSingleLight") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "PostClassification1D") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "StrengthVolumeNull") as FragmentShader;
            fragList.Add(frag);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "VolumeShaderLitSurface") as FragmentShader;
            fragList.Add(frag);
            ShaderProgram dvr_lighting = new ShaderProgram("DVR-Lighting", vertList, fragList);
            //glPanel.Link(dvr_lighting);
            AssetManager.Instance.Add(dvr_lighting);

            //Ray casting (remember - use not with ROI, but with Boundary!)
            fragList = new List<FragmentShader>(1);
            vertList = new List<VertexShader>(1);
            vert = AssetManager.Instance.Find(typeof(VertexShader), "VertexTexCoord") as VertexShader;
            //vert = new VertexShader("RayCaster", GLSLEditorCtrl.defaultVertShader);
            vertList.Add(vert);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "RayCaster") as FragmentShader;
            fragList.Add(frag);
            ShaderProgram rayCaster = new ShaderProgram("Ray Caster", vertList, fragList);
            //glPanel.Link(rayCaster);
            AssetManager.Instance.Add(rayCaster);

            //Pre-Integrated Volume Rendering (use with boundary also)
            fragList = new List<FragmentShader>(1);
            vertList = new List<VertexShader>(1);
            vert = AssetManager.Instance.Find(typeof(VertexShader), "VertexTexCoord") as VertexShader;
            //vert = new VertexShader("PreIntegratedVR", GLSLEditorCtrl.defaultVertShader);
            vertList.Add(vert);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "PreIntegratedVR") as FragmentShader;
            fragList.Add(frag);
            ShaderProgram preIntegratedVR = new ShaderProgram("Pre-Integrated VR", vertList, fragList);
            //glPanel.Link(preIntegratedVR);
            AssetManager.Instance.Add(preIntegratedVR);

            //Flow Vis 2D
            fragList = new List<FragmentShader>(1);
            vertList = new List<VertexShader>(1);
            vert = AssetManager.Instance.Find(typeof(VertexShader), "VertexWithTexture") as VertexShader;
            vertList.Add(vert);
            frag = AssetManager.Instance.Find(typeof(FragmentShader), "FlowVis2D") as FragmentShader;
            fragList.Add(frag);
            ShaderProgram flowVis2D = new ShaderProgram("Flow Vis 2D", vertList, fragList);
            AssetManager.Instance.Add(flowVis2D);
        }

        private void LoadShaders(string searchDir)
        {
            if (System.IO.Directory.Exists(searchDir))
            {
                string[] vertRoutines = System.IO.Directory.GetFiles(searchDir, "*.vert", System.IO.SearchOption.AllDirectories);
                foreach (string vertFile in vertRoutines)
                {
                    //String shaderName = vertFile.Replace(searchDir, "");
                    String shaderName = System.IO.Path.GetFileNameWithoutExtension(vertFile);
                    string shaderSource = ShaderRoutine.LoadFromFile(vertFile);
                    VertexShader shaderRoutine = new VertexShader(shaderName, shaderSource);
                    AssetManager.Instance.Add(shaderRoutine);
                }
                string[] fragRoutines = System.IO.Directory.GetFiles(searchDir, "*.frag", System.IO.SearchOption.AllDirectories);
                foreach (string fragFile in fragRoutines)
                {
                    //String shaderName = fragFile.Replace(searchDir, "");
                    String shaderName = System.IO.Path.GetFileNameWithoutExtension(fragFile);
                    string shaderSource = ShaderRoutine.LoadFromFile(fragFile);
                    FragmentShader shaderRoutine = new FragmentShader(shaderName, shaderSource);
                    AssetManager.Instance.Add(shaderRoutine);
                }
            }
        }

        private void LoadMaterials()
        {
            MaterialProxy material = new MaterialProxy("DVR-PostClassify");
            material.Shader = AssetManager.Instance.Find(typeof(ShaderProgram), "DVR-PostClass") as ShaderProgram;
            AssetManager.Instance.Add(material);
        }

        private void LoadLights()
        {
            LightCollectionProxy noLightsCollection = new LightCollectionProxy("No Lights");
            AssetManager.Instance.Add(noLightsCollection);

            LightCollectionProxy singleLightCollection = new LightCollectionProxy("Single Light");
            DirectionalLightProxy directionalLight = new DirectionalLightProxy("directional light");
            singleLightCollection.LightProxies.Add(directionalLight);
            AssetManager.Instance.Add(singleLightCollection);

            LightCollectionProxy fourLightCollection = new LightCollectionProxy("Four lights");
            List<DirectionalLightProxy> lights = new List<DirectionalLightProxy>(4);
            lights.Add(new DirectionalLightProxy("directional light [0]"));
            lights.Add(new DirectionalLightProxy("directional light [1]"));
            lights.Add(new DirectionalLightProxy("directional light [2]"));
            lights.Add(new DirectionalLightProxy("directional light [3]"));
            foreach (DirectionalLightProxy light in lights)
            {
                fourLightCollection.LightProxies.Add(light);
            }
            AssetManager.Instance.Add(fourLightCollection);
        }

        private void CreateRenderServer(Control parentControl)
        {
            glPanel = null;
            if (parentControl != null)
            {
                glPanel = new OpenGLPanel();
                glPanel.Dock = DockStyle.Fill;
                parentControl.Controls.Add(glPanel);
                //
                // Set the background colors to the underlying control color.
                //
                this.glPanel.SetBackgroundColor((float)parentControl.BackColor.R / 255.0f,
                    (float)parentControl.BackColor.G / 255.0f,
                    (float)parentControl.BackColor.B / 255.0f);
            }
            RenderServer newServer = new RenderServer(view, glPanel);
            glPanel = newServer.Panel as OpenGLPanel;

            //
            // AHHHRG!!! Windows .Net 1.1 only handles the arrow keys on a keyup event!!!
            // Hopefully they will fix this in future version, otherwise we need to
            // override the ProcessDialogKey method. Yuck!!!
            //
            //this.glPanel.KeyUp += new KeyEventHandler(cameraCtrl.KeyTrackballArrows);
            //this.glPanel.KeyDown += new KeyEventHandler(cameraCtrl.KeyTrackballNumPad);
            //this.glPanel.KeyPress += new KeyPressEventHandler(cameraCtrl.KeyTrackball);
            // for Simple Test
            this.glPanel.KeyPress += new KeyPressEventHandler(KeyPressHandler);
            this.glPanel.KeyDown += new KeyEventHandler(KeyBeginManipulation);
            this.glPanel.KeyUp += new KeyEventHandler(KeyEndManipulation);
            //
            // Create the OpenGL asset manager.
            //
            OhioState.Graphics.OpenGL.AssetManagerGL openGLAssetManager = new OhioState.Graphics.OpenGL.AssetManagerGL();
            glPanel.ResourceManager = openGLAssetManager;
        }

        private void InitializeShaders(AppSettingsReader appSettingReader, IRenderPanel panel)
        {
            //
            // Set up default shaders from config. file
            //
            Object obj = appSettingReader.GetValue("DefaultVertShader", typeof(String));
            GLSLEditorCtrl.defaultVertShader = (String)obj;
            obj = appSettingReader.GetValue("DefaultFragShader", typeof(String));
            GLSLEditorCtrl.defaultFragShader = (String)obj;

            glslShaderEditorCtrl.CompileEvent += new GLSLEditorCtrl.CompileHandler(panel.Compile);
            glslShaderEditorCtrl.LinkEvent += new GLSLLinkerCtrl.LinkHandler(panel.Link);
            IList<IAssetManaged> shaders = AssetManager.Instance.FindAll(typeof(ShaderProgram));
            foreach (IAssetManaged asset in shaders)
            {
                ShaderProgram program = asset as ShaderProgram;
                if (program != null)
                    glPanel.Link(program);
            }
        }

        private void CreateControllers(ICamera camera)
        {
            examiner1 = new ExaminerMouseHandler();
            examiner1.OwnerControl = glPanel;

            examiner1.AddSlave(camera as ITransform);
            examiner1.AddSlave(camera as IZoomLens);

            planeMouseHandler = new PlaneMouseHandler();
            planeMouseHandler.OwnerControl = glPanel;
            planeMouseHandler.Camera = camera;
        }

        private void InitializeControls()
        {
            _materialList =AssetManager.Instance.FindAll(typeof(IMaterial)); // new List<IAssetManaged>();
            drawableMaterialGrid1.SetMaterialList(_materialList);
            AssetManager.Instance.AssetAdded += new IAssetManagedHandler(addDrawableMaterialView);


            fisheyeMaterialDropDownControl.Init(typeof(MaterialProxy));
            assetManagerDropDownControl1.Init(typeof(MaterialProxy));
            DeformDropDownControl.Init(typeof(MaterialProxy));
            transferFunctionManager.createdPreintegratedTFEvent +=
                new TransferFunctionManager.CreatedPreintegratedTF(createPreintegratedTF);
        }

        private void InitializeRemoting()
        {
            //RemotingServices.Marshal(_view, "Main View");
            //RemotingServices.Marshal(RemoteEventHandler.Instance, "Event Helper");
            RemotingServices.Marshal(AssetManager.Instance, "Asset Manager");
        }
        #endregion Contructors and Initialization

        #region Keyboard Callbacks
        public void KeyBeginManipulation(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            mainCamera.BeginManipulation();
        }

        public void KeyEndManipulation(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            mainCamera.EndManipulation();
        }

        public void KeyPressHandler(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            //if (e.KeyChar == 'i' || e.KeyChar == 'I')
            //{
            //    GLRender.slicingAlignment = GLRender.SlicingType.IMAGE_ALIGNED;
            //}

            //else if (e.KeyChar == 'o' || e.KeyChar == 'O')
            //{
            //    GLRender.slicingAlignment = GLRender.SlicingType.OBJECT_ALIGNED;
            //}

            //else if (e.KeyChar == 'l' || e.KeyChar == 'L')
            //{
            //    if (GLRender.outlinesOn)
            //        GLRender.outlinesOn = false;
            //    else
            //        GLRender.outlinesOn = true;
            //}

            //else if (e.KeyChar == '+' || e.KeyChar == '=')
            //{
            //    ROIGUI.ROIInfo.M_nLODLevel += ROIGUI.ROIInfo.M_nLODStep;
            //    //_renderWork.M_pVolumeShader.SetSliceSpacing( _renderWork.CalcLODLevel() );
            //}
            //else if (e.KeyChar == '-' || e.KeyChar == '_')
            //{
            //    ROIGUI.ROIInfo.M_nLODLevel -= ROIGUI.ROIInfo.M_nLODStep;
            //    //_renderWork.M_pVolumeShader.SetSliceSpacing( _renderWork.CalcLODLevel() );
            //}
            this.glPanel.Invalidate();
        }
        #endregion

        #region Drawing Code
        protected void OpenGLForm_Resize(object sender, System.EventArgs e)
        {
            if (view != null)
            {
                view.Viewport = new Viewport(new Vector2i(0, 0), new Vector2i(glPanel.Width, glPanel.Height));
                float aspect = (float)(glPanel.Width) / (float)glPanel.Height;
                this.mainCamera.AspectRatio = aspect;
                this.glPanel.Invalidate();
            }
        }

        private void invalidateEvent(IAssetManaged obj)
        {
            this.glPanel.Invalidate();
        }
        #endregion Drawing Code

        #region Asset Manager Listeners
        void addDrawableMaterialView(IAssetManaged asset)
        {
            if (asset is IDrawable)
            {
                if (this.InvokeRequired)
                {
                    object[] foo = new object[1];
                    addDrawableRowDelegate del = new addDrawableRowDelegate(addDrawableRow);
                    foo[0] = asset;
                    this.Invoke(del, foo);
                }
                else
                {
                    addDrawableRow(asset);
                }
            }
            else if (asset is IMaterial)
            {
                //IMaterial materialObj = obj as IMaterial;
                if (this.InvokeRequired)
                {
                    object[] foo = new object[2];
                    addMaterialItemDelegate del = new addMaterialItemDelegate(addMaterialItem);
                    foo[0] = asset.Name;
                    foo[1] = asset;
                    this.Invoke(del, foo);
                }
                else
                {
                    addMaterialItem(asset.Name, asset);
                }
            }
        }

        void addDrawableRow(IAssetManaged obj)
        {
            IDrawable drawableObj = obj as IDrawable;
            int row1 = drawableMaterialGrid1.Rows.Add();
            drawableMaterialGrid1.Rows[row1].Cells["AssetsColumn"].Value = obj;
            drawableMaterialGrid1.Rows[row1].Cells["MaterialsColumn"].Value = drawableObj.Material;
        }

        void addMaterialItem(string name, IAssetManaged materialObj)
        {
            if (materialObj is IMaterial)
            {
                _materialList.Add(materialObj);
                drawableMaterialGrid1.SetMaterialList(_materialList);
            }
        }
        #endregion

        #region File Menu
        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (projSaveFileDialog.ShowDialog() == DialogResult.OK)
            {
                AssetManager.Instance.SaveToFile(projSaveFileDialog.FileName);
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void volumeFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (volumeOpenFileDialog.ShowDialog() == DialogResult.OK)
            {
                String filename = this.volumeOpenFileDialog.FileName;
                String extension = System.IO.Path.GetExtension(filename);
                String name = Path.GetFileName(filename);

                if (extension == ".vol" || extension == ".dat")
                {
                    Volume vol = new Volume(filename);
                    if (AssetManager.Instance.Find(typeof(Volume), name) == null)
                        AssetManager.Instance.Add((Volume)vol);

                    VolumeHistogram volumeHistogram = new VolumeHistogram(name + "_histogram", filename);
                    if (AssetManager.Instance.Find(typeof(VolumeHistogram), name + "_histogram") == null)
                        AssetManager.Instance.Add((VolumeHistogram)volumeHistogram);

                    VolumeGradientHistogram gradientHistogram = new VolumeGradientHistogram(name + "_grad_histogram", filename);
                    if (AssetManager.Instance.Find(typeof(VolumeGradientHistogram), name + "_grad_histogram") == null)
                        AssetManager.Instance.Add((VolumeGradientHistogram)gradientHistogram);
                }

                else if (extension == ".raw")
                {
                    VolumeDim volDim = new VolumeDim(filename);
                    if (volDim.ShowDialog() == DialogResult.OK)
                    {
                        TexelFormat type = new TexelFormat();
                        type.Type = (ByteFormat)volDim.TexelType.Type;
                        type.Format = OhioState.Graphics.ImageFormat.ALPHA;
                        Volume vol = (Volume)new Volume(filename, volDim.XDim, volDim.YDim, volDim.ZDim, type);
                        if (AssetManager.Instance.Find(typeof(Volume), name) == null)
                            AssetManager.Instance.Add((Volume)vol);

                        VolumeHistogram volumeHistogram = new VolumeHistogram(name + "_histogram", filename);
                        if (AssetManager.Instance.Find(typeof(VolumeHistogram), name + "_histogram") == null)
                            AssetManager.Instance.Add((VolumeHistogram)volumeHistogram);

                        VolumeGradientHistogram gradientHistogram = new VolumeGradientHistogram(name + "_grad_histogram", filename);
                        if (AssetManager.Instance.Find(typeof(VolumeGradientHistogram), name + "_grad_histogram") == null)
                            AssetManager.Instance.Add((VolumeGradientHistogram)gradientHistogram);
                    }
                }

            }
        }

        private void visualizationProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (projOpenFileDialog.ShowDialog() == DialogResult.OK)
            {
                AssetManager.Instance.LoadFromFile(projOpenFileDialog.FileName);
            }
            // TODO: we need to delete the old view or views and reattach any
            //  that were just read in to the ViewHandlers.
        }

        private void textureFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (texOpenFileDialog.ShowDialog() == DialogResult.OK)
            {
                String filename = this.texOpenFileDialog.FileName;
                String name = Path.GetFileNameWithoutExtension(filename);
                AssetManager assetManager = AssetManager.Instance;

                if (assetManager.Find(typeof(TexImage), name) == null)
                {
                    TexelFormat format = new TexelFormat();
                    format.Type = ByteFormat.BYTE;
                    format.Format = OhioState.Graphics.ImageFormat.RGBA;
                    //Hack for now
                    TexImage texImage = new TexImage(name, filename);
                    assetManager.Add((TexImage)texImage);

                    ImageHistogram imageHistogram = new ImageHistogram(name + "_histogram", filename);
                    if (assetManager.Find(typeof(ImageHistogram), name + "_histogram") == null)
                        assetManager.Add((ImageHistogram)imageHistogram);
                }
            }
        }


        private void SegmentFilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            segmentOpenFileDialog.ShowDialog();
            String[] segFileNames = new String[256];
            String[] names = new String[256];
            segFileNames = segmentOpenFileDialog.FileNames;
            for (int cnt = 0; cnt < segFileNames.Length; cnt++)
                names[cnt] = Path.GetFileName(segFileNames[cnt]);
            AssetManager assetManager = AssetManager.Instance;

            TexelFormat format = new TexelFormat();
            format.Type = ByteFormat.BYTE;
            format.Format = OhioState.Graphics.ImageFormat.RGBA;
            Segment segment = new Segment(segFileNames, names, format);
            if (assetManager.Find(typeof(Segment), names[0]) == null)
                assetManager.Add((Segment)segment);

        }

        private void vectorFieldToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AssetManager assetManager = AssetManager.Instance;

            TexelFormat format = new TexelFormat();
            format.Type = ByteFormat.BYTE;
            format.Format = OhioState.Graphics.ImageFormat.RGBA;

            //Hack for now
            //String name = "Vector Field";
            //VectorField vField = new VectorField(name, "vect.dat");
            //if (assetManager.Find(typeof(VectorField), name) == null)
            //    assetManager.Add((VectorField)vField);

            //VectorField3D vField3D = new VectorField3D("tornadoPC_48.vec", 48, 48, 48, format);
            //if (assetManager.Find(typeof(VectorField3D), "tornado") == null)
            //    assetManager.Add((VectorField3D)vField3D);
            OpenFileDialog fd = new OpenFileDialog();
            fd.Filter = "flow data files (*.dat;*.vec;*.vect)|*.dat;*.vec;*.vect";
            if (fd.ShowDialog() == DialogResult.OK)
            {
                String name = Path.GetFileName(fd.FileName);
                if(fd.FileName.EndsWith("dat"))
                {
                    VectorField vField = new VectorField(name, fd.FileName);
                    if (assetManager.Find(typeof(VectorField), name) == null)
                        assetManager.Add((VectorField)vField);
                }
                else if (fd.FileName.EndsWith("vect"))
                {
                    VectorField vField = new VectorField(name, fd.FileName, true);
                    if (assetManager.Find(typeof(VectorField), name) == null)
                        assetManager.Add((VectorField)vField);
                }
                else if (fd.FileName.EndsWith("vec"))
                {
                    VolumeDim volDim = new VolumeDim(fd.FileName);
                    if (volDim.ShowDialog() == DialogResult.OK)
                    {
                        TexelFormat type = new TexelFormat();
                        format.Type = (ByteFormat)volDim.TexelType.Type;

                        VectorField3D vField3D = new VectorField3D(fd.FileName, volDim.XDim, volDim.YDim, volDim.ZDim, format);
                        if (assetManager.Find(typeof(VectorField3D), name) == null)
                            assetManager.Add((VectorField3D)vField3D);
                    }
                }
            }
        }
        #endregion

        #region View Menu
        //
        // TODO - We need a create camera dialog
        //
        bool menuTest = false;
        private void addCameraToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string name = "New Camera";
            ICamera cam = CreateCamera(name);
            AssetManager.Instance.Add(cam as IAssetManaged);
            //cameraSwitch.AddCamera(cam);
            //cameraSwitch.SelectCamera(name);
            menuTest = true;
        }

        private void cameraSelected(object sender, EventArgs e)
        {
            string name = sender.ToString();
            this.cameraSwitch.SelectCamera(name);
        }

        private void viewToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            if (menuTest == true)
            {
                viewToolStripMenuItem.DropDownItems.Add("-");
                menuTest = false;
            }
            int numItems = viewToolStripMenuItem.DropDownItems.Count;
            for (int i = numItems-1; i >= 3; i--)
            {
                viewToolStripMenuItem.DropDownItems.RemoveAt(i);
            }
            List<IAssetManaged> cameras = AssetManager.Instance.FindAll(typeof(ICamera));
            foreach (IAssetManaged asset in cameras)
            {
                if( asset.Name != "MainCamera")
                    viewToolStripMenuItem.DropDownItems.Add(asset.Name,null,cameraSelected);
            }
        }
        #endregion View Menu

        #region Tools Menu
        private void OSUVolume_saveScreenshot(object sender, EventArgs e)
        {
            //CaptureScreen();

            //if (saveFileDialog == null)
            //{
            //    saveFileDialog = new SaveFileDialog();
            //    saveFileDialog.Filter =
            //        "PNG Files (*.png)|*.png";
            //}
            //DialogResult dialogResult = saveFileDialog.ShowDialog(this);
            //if (dialogResult == DialogResult.OK)
            //{
            //    string filename = saveFileDialog.FileName.Substring(0, saveFileDialog.FileName.Length - 4);
            //    _viewGL.SaveScreenshot(filename, "png");
            //}
        }

        //private void CaptureScreen()
        //{
        //    if (saveFileDialog == null)
        //    {
        //        saveFileDialog = new SaveFileDialog();
        //        saveFileDialog.Filter = "PNG Files (*.png)|*.png";
        //    }
        //    DialogResult dialogResult = saveFileDialog.ShowDialog(this);
        //    if (dialogResult != DialogResult.OK)
        //    {
        //        return;
        //    }
        //    string filename = saveFileDialog.FileName.Substring(0, saveFileDialog.FileName.Length - 4);
            
        //    int layer_num = 0;
        //    foreach (LayerTextureProxy textureProxy in AssetManager.Instance.GetItem(typeof(LayerTextureProxy)))
        //    {
        //        TextureWriterProxy textureWriterProxy = new TextureWriterProxy(textureProxy);
        //        TextureWriterHandler textureWriterHandler = new TextureWriterHandler(glPanel, textureWriterProxy);
        //        Bitmap bitmap = textureWriterHandler.GetBitmap();
        //        bitmap.Save(filename + "_local_" + layer_num + ".png", System.Drawing.Imaging.ImageFormat.Png);

        //        //how to select which windows we are going to get screenshots from?
        //        //now we get all of them...

        //        int[,] sizes;
        //        byte[][] result = RemoteEventHandler.Instance.GetScreenshots(textureWriterProxy, out sizes);
        //        for (int i = 0; i < result.GetLength(0); i++)
        //        {
        //            int bitmapWidth = sizes[i,0], bitmapHeight = sizes[i,1];
        //            Bitmap bm = BitmapHelper.GetBitmapFromByteArray(result[i], bitmapWidth, bitmapHeight);
        //            bm.Save(filename + "_remote_" + i + "_" + layer_num + ".png", System.Drawing.Imaging.ImageFormat.Png);
        //        }
        //        layer_num++;
        //    }
        //}
        #endregion

        #region Windows Menu
        //
        // This code drives all the logic behind showing and hiding all the various panels of the UI.
        //  This requires a little bit of cleverness because hiding some panels forces others to come
        //  out of hiding.  Simple stuff but requires an annoyingly large amount of code.
        //

        //
        // Apparently tab controls are silly and dont update correctly so
        //  this function tells them to redraw explicitly.  This seems to cause some slowdown...
        //  Thanks Microsoft :-(
        //
        private void InvalidateTabControls()
        {
            //roiTabControl.Invalidate();
            shapeControl1.Invalidate();
            glslShaderEditorCtrl.Invalidate();
            infoTabControl.Invalidate();
            MaterialTabControl.Invalidate();
            layersTabControl.Invalidate();
        }

        private void splitContainer_SplitterMoved(object sender, SplitterEventArgs e)
        {
            //InvalidateTabControls();
        }
        
        private void regionsOfInterestToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (leftBaseSplitContainer.Panel1Collapsed)
            {
                leftBaseSplitContainer.Panel1Collapsed = false;
                leftSplitContainer.Panel1Collapsed = false;
                leftSplitContainer.Panel2Collapsed = true;
                regionsOfInterestToolStripMenuItem.Checked = true;
            }
            else if (leftSplitContainer.Panel2Collapsed)
            {
                leftBaseSplitContainer.Panel1Collapsed = true;
                regionsOfInterestToolStripMenuItem.Checked = false;
            }
            else
            {
                leftSplitContainer.Panel1Collapsed = !leftSplitContainer.Panel1Collapsed;
                regionsOfInterestToolStripMenuItem.Checked = !leftSplitContainer.Panel1Collapsed;
            }
            InvalidateTabControls();
            
        }

        private void shadersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (leftBaseSplitContainer.Panel1Collapsed)
            {
                leftBaseSplitContainer.Panel1Collapsed = false;
                leftSplitContainer.Panel2Collapsed = false;
                leftSplitContainer.Panel1Collapsed = true;
                shadersToolStripMenuItem.Checked = true;
            }
            else if (leftSplitContainer.Panel1Collapsed)
            {
                leftBaseSplitContainer.Panel1Collapsed = true;
                shadersToolStripMenuItem.Checked = false;
            }
            else
            {
                leftSplitContainer.Panel2Collapsed = !leftSplitContainer.Panel2Collapsed;
                shadersToolStripMenuItem.Checked = !leftSplitContainer.Panel2Collapsed;
            }
            InvalidateTabControls();
        }

        private void transferFunctionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            middleSplitContainer.Panel2Collapsed = !middleSplitContainer.Panel2Collapsed;
            transferFunctionToolStripMenuItem.Checked = !middleSplitContainer.Panel2Collapsed;
            InvalidateTabControls();
        }

        private void infoNavigatorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (rightBaseSplitContainer.Panel2Collapsed)
            {
                rightBaseSplitContainer.Panel2Collapsed = false;
                topRightSplitContainer.Panel1Collapsed = false;
                topRightSplitContainer.Panel2Collapsed = true;
                infoNavigatorToolStripMenuItem.Checked = true;
            }
            else if (topRightSplitContainer.Panel2Collapsed)
            {
                rightBaseSplitContainer.Panel2Collapsed = true;
                infoNavigatorToolStripMenuItem.Checked = false;
            }
            else
            {
                topRightSplitContainer.Panel1Collapsed = !topRightSplitContainer.Panel1Collapsed;
                infoNavigatorToolStripMenuItem.Checked = !topRightSplitContainer.Panel1Collapsed;
            }
            InvalidateTabControls();
        }

        private void historyViewerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (rightBaseSplitContainer.Panel2Collapsed)
            {
                rightBaseSplitContainer.Panel2Collapsed = false;
                topRightSplitContainer.Panel2Collapsed = false;
                topRightSplitContainer.Panel1Collapsed = true;
                bottomRightSplitContainer.Panel1Collapsed = false;
                bottomRightSplitContainer.Panel2Collapsed = true;
                historyViewerToolStripMenuItem.Checked = true;
            }
            else if (topRightSplitContainer.Panel2Collapsed)
            {
                topRightSplitContainer.Panel2Collapsed = false;
                bottomRightSplitContainer.Panel1Collapsed = false;
                bottomRightSplitContainer.Panel2Collapsed = true;
                historyViewerToolStripMenuItem.Checked = true;
            }
            else if ((topRightSplitContainer.Panel1Collapsed) && (bottomRightSplitContainer.Panel2Collapsed))
            {
                rightBaseSplitContainer.Panel2Collapsed = true;
                historyViewerToolStripMenuItem.Checked = false;
            }
            else if (bottomRightSplitContainer.Panel2Collapsed) // but top right panel1 not collapsed
            {
                topRightSplitContainer.Panel2Collapsed = true;
                historyViewerToolStripMenuItem.Checked = false;
            }
            else
            {
                bottomRightSplitContainer.Panel1Collapsed = !bottomRightSplitContainer.Panel1Collapsed;
                historyViewerToolStripMenuItem.Checked = !bottomRightSplitContainer.Panel1Collapsed;
            }
            InvalidateTabControls();
        }

        private void layersEditorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (rightBaseSplitContainer.Panel2Collapsed)
            {
                rightBaseSplitContainer.Panel2Collapsed = false;
                topRightSplitContainer.Panel2Collapsed = false;
                topRightSplitContainer.Panel1Collapsed = true;
                bottomRightSplitContainer.Panel2Collapsed = false;
                bottomRightSplitContainer.Panel1Collapsed = true;
                layersEditorToolStripMenuItem.Checked = true;
            }
            else if (topRightSplitContainer.Panel2Collapsed)
            {
                topRightSplitContainer.Panel2Collapsed = false;
                bottomRightSplitContainer.Panel2Collapsed = false;
                bottomRightSplitContainer.Panel1Collapsed = true;
                layersEditorToolStripMenuItem.Checked = true;
            }
            else if ((topRightSplitContainer.Panel1Collapsed) && (bottomRightSplitContainer.Panel1Collapsed))
            {
                rightBaseSplitContainer.Panel2Collapsed = true;
                layersEditorToolStripMenuItem.Checked = false;
            }
            else if (bottomRightSplitContainer.Panel1Collapsed) // but top right panel1 not collapsed
            {
                topRightSplitContainer.Panel2Collapsed = true;
                layersEditorToolStripMenuItem.Checked = false;
            }
            else
            {
                bottomRightSplitContainer.Panel2Collapsed = !bottomRightSplitContainer.Panel2Collapsed;
                layersEditorToolStripMenuItem.Checked = !bottomRightSplitContainer.Panel2Collapsed;
            }
            InvalidateTabControls();
        }

        private void turnOffAllControlsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            leftBaseSplitContainer.Panel1Collapsed = true;
            rightBaseSplitContainer.Panel2Collapsed = true;
            middleSplitContainer.Panel2Collapsed = true;
            shadersToolStripMenuItem.Checked = false;
            regionsOfInterestToolStripMenuItem.Checked = false;
            transferFunctionToolStripMenuItem.Checked = false;
            infoNavigatorToolStripMenuItem.Checked = false;
            historyViewerToolStripMenuItem.Checked = false;
            layersEditorToolStripMenuItem.Checked = false;
        }

        private void turnOnAllControlsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            leftBaseSplitContainer.Panel1Collapsed = false;
            rightBaseSplitContainer.Panel2Collapsed = false;
            middleSplitContainer.Panel2Collapsed = false;
            leftSplitContainer.Panel1Collapsed = false;
            leftSplitContainer.Panel2Collapsed = false;
            topRightSplitContainer.Panel1Collapsed = false;
            topRightSplitContainer.Panel2Collapsed = false;
            bottomRightSplitContainer.Panel1Collapsed = false;
            bottomRightSplitContainer.Panel2Collapsed = false;

            shadersToolStripMenuItem.Checked = true;
            regionsOfInterestToolStripMenuItem.Checked = true;
            transferFunctionToolStripMenuItem.Checked = true;
            infoNavigatorToolStripMenuItem.Checked = true;
            historyViewerToolStripMenuItem.Checked = true;
            layersEditorToolStripMenuItem.Checked = true;
            InvalidateTabControls();
        }
        #endregion

        #region Help Menu
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBoxOSU aboutBox = new AboutBoxOSU();
            aboutBox.ShowDialog();
        }
        #endregion

        #region Form Events
        private void OSUVolume_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.WindowState == FormWindowState.Maximized)
            {
                frmSettings.AppState = FormWindowState.Maximized;
            }
            if (this.WindowState == FormWindowState.Normal)
            {
                frmSettings.AppState = FormWindowState.Normal;
                frmSettings.AppSize = this.Size;
                frmSettings.AppLocation = this.Location;
            }
            else
            {
                frmSettings.AppSize = this.RestoreBounds.Size;
                frmSettings.AppLocation = this.RestoreBounds.Location;
            }

            frmSettings.Save();
        }

        private void OSUVolume_Load(object sender, EventArgs e)
        {
            this.Size = Properties.Settings.Default.AppSize;
            this.WindowState = Properties.Settings.Default.AppState;
            this.Location = Properties.Settings.Default.AppLocation;
        }

        private void glslShaderEditorCtrl_Resize(object sender, EventArgs e)
        {
            Control control = (Control)sender;
            OhioStateVolumeRenderer.Properties.Settings.Default.leftBaseSplitDistance = control.Size.Width;
        }
        #endregion

        #region Masking and Fisheye support
        private void OSUVolume_fisheyeCheckboxClicked(object sender, EventArgs e)
        {
            if (((CheckBox)sender).CheckState == CheckState.Checked)
            {
                FisheyeManager.Instance.SetModeActive(glPanel, this);
                fisheyeMaterialDropDownControl.Enabled = true;
                fisheyeNumericUpDownRadius.Enabled = true;
                fisheyeNumericUpDownZoom.Enabled = true;
            }
            else
            {
                FisheyeManager.Instance.SetModeInactive();
                fisheyeMaterialDropDownControl.Enabled = false;
                fisheyeNumericUpDownRadius.Enabled = false;
                fisheyeNumericUpDownZoom.Enabled = false;
            }
        }

        private void OSUVolume_fisheyeMaterialControlSelected(IAssetManaged obj)
        {
            FisheyeManager.Instance.setCurrentMaterial(((MaterialProxy)obj));
        }

        private void OSUVolume_fisheyeLensRadiusChanged(object sender, EventArgs e)
        {
            FisheyeManager.Instance.SetLensRadius( Decimal.ToSingle(((NumericUpDown)sender).Value));
        }

        private void OSUVolume_fisheyeZoomLevelChanged(object sender, EventArgs e)
        {
            FisheyeManager.Instance.SetZoomLevel(Decimal.ToSingle(((NumericUpDown)sender).Value));
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            if (((CheckBox)sender).CheckState == CheckState.Checked)
            {
                MaskingManager.Instance.SetModeActive(glPanel, this);
                assetManagerDropDownControl1.Enabled = true;
                numericUpDown2.Enabled = true;
             }
            else
            {
                MaskingManager.Instance.SetModeInactive();
                assetManagerDropDownControl1.Enabled = false;
                numericUpDown2.Enabled = false;
            }
        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {
            MaskingManager.Instance.SetLensRadius(Decimal.ToSingle(((NumericUpDown)sender).Value));
        }

        private void assetManagerDropDownControl1_SelectedEvent(IAssetManaged obj)
        {
            MaskingManager.Instance.setCurrentMaterial(((MaterialProxy)obj));
        }


        //private void DeformDropDownControl_SelectedEvent(IAssetManaged obj)
        //{
        //    Deformation.Instance.setCurrentMaterial(((MaterialProxy)obj));
        //}

        private void DeformcheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (((CheckBox)sender).CheckState == CheckState.Checked)
            {
                Deformation.Instance.SetModeActive(glPanel, this);
                DeformDropDownControl.Enabled = true;
            }
            else
            {
                Deformation.Instance.SetModeInactive();
                DeformDropDownControl.Enabled = false;
            }
        }

        private void DeformDropDownControl_SelectedEvent_1(IAssetManaged obj)
        {
            Deformation.Instance.setCurrentMaterial(((MaterialProxy)obj));
        }
        #endregion

        #region Camera support
        private void AddCameraItemEvent(IAssetManaged asset)
        {
            ICamera camera = asset as ICamera;
            if (camera != null)
                cameraSwitch.AddCamera(camera);
        }
        #endregion

        //PlaneMouseHandler planeMouseHandler;
        private void planeControlCheckBoxClicked(object sender, EventArgs e)
        {
            if (planeControlCheckBox.Checked)
            {
                examiner1.RemoveSlave(mainCamera as ITransform);
                examiner1.RemoveSlave(mainCamera as IZoomLens);
                planeMouseHandler.TurnOn();
            }
            else
            {
                examiner1.AddSlave(mainCamera as ITransform);
                examiner1.AddSlave(mainCamera as IZoomLens);
                planeMouseHandler.TurnOff();
            }
        }

        #region Transfer Function events
        private void createPreintegratedTF(IAssetManaged transferFunction)
        {
            TransferFunction tf = (TransferFunction)transferFunction;
            if (tf == null)
                return;
            if (AssetManager.Instance.Find(typeof(TexImage), tf.Name + "-Integrated") == null)
            {
                TexImage preintegratedTF = new TexImage(tf.Name + "-Integrated", new byte[] { 0 }, 256, 256);
                AssetManager.Instance.Add(preintegratedTF);
                tf.AddChangingEventHandler(updatePreintegratedTF);
                updatePreintegratedTF(tf);
            }
        }

        private void updatePreintegratedTF(IAssetManaged asset)
        {
            TransferFunction tf = (TransferFunction)asset;
            
            //integrate the transfer function
            ushort[] result = new ushort[256 * 256 * 4];
            byte[] byteResult = new byte[256 * 256 * 4];
            double step = 1.0;
            int dim = 0;
            byte[] values = tf.GetTextureByte(out dim);
            int length = 256;//dim / tf.TexelType.NumChannels;
            for (double sFront = 0; sFront < length; sFront += step)
            {
                for (double sBack = sFront; sBack < length; sBack += step)
                {
                    //calculate Riemann sum from sFront to sBack
                    double R = 0, G = 0, B = 0, A = 0;
                    int num_steps = 0;
                    for (double cv = sFront; cv <= sBack; cv += step)//cv means currentValue
                    {
                        num_steps++;

                        //use opacity-attenuated colors
                        double alpha = (double)(values[(int)cv * 4 + 3]) / 256.0;//now alpha is from 0 to 1

                        R += (values[(int)cv * 4]);
                        G += (values[(int)cv * 4 + 1]);
                        B += (values[(int)cv * 4 + 2]);
                        A += (values[(int)cv * 4 + 3]);
                    }

                    byteResult[1024 * (int)sBack + (int)sFront * 4] = (byte)(R / num_steps);
                    byteResult[1024 * (int)sBack + (int)sFront * 4 + 1] = (byte)(G / num_steps);
                    byteResult[1024 * (int)sBack + (int)sFront * 4 + 2] = (byte)(B / num_steps);
                    byteResult[1024 * (int)sBack + (int)sFront * 4 + 3] = (byte)(A / num_steps);

                    //fill the whole texture, not only upper triangle (make symmetric around y = x,
                    //thus swap sFront with sBack)
                    byteResult[1024 * (int)(sFront) + (int)(sBack) * 4] = (byte)(R / num_steps);
                    byteResult[1024 * (int)(sFront) + (int)(sBack) * 4 + 1] = (byte)(G / num_steps);
                    byteResult[1024 * (int)(sFront) + (int)(sBack) * 4 + 2] = (byte)(B / num_steps);
                    byteResult[1024 * (int)(sFront) + (int)(sBack) * 4 + 3] = (byte)(A / num_steps);
                }
            }

            //this should always execute (there should always be preintegrated tf)
            if (AssetManager.Instance.Find(typeof(TexImage), tf.Name + "-Integrated") != null)
            {
                TexImage oldTF = (TexImage)AssetManager.Instance.Find(typeof(TexImage), tf.Name + "-Integrated");
                oldTF.BeginManipulation();
                oldTF.ImageByte = byteResult;
                oldTF.EndManipulation();
            }
        }
        #endregion

        private DataServerConnectDialog dataServerConnectDialog;
        private void dataServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dataServerConnectDialog == null)
            {
                dataServerConnectDialog = new DataServerConnectDialog();
                dataServerConnectDialog.connectEvent += 
                    new DataServerConnectDialog.Connecting(dataServerDialogConnecting);

                RemotingConfiguration.Configure("./RemotingConfiguration.exe.config", false);
            }
            dataServerConnectDialog.ShowDialog(this);
        }

        public void dataServerDialogConnecting(object o, EventArgs args)
        {
            String dataServerAddress = dataServerConnectDialog.GetText();

            AssetManager dataServerAssetManager = 
                (AssetManager)Activator.GetObject(typeof(AssetManager), 
                "tcp://" + dataServerAddress + ":8007/" + "DataServerAssetManager");

            List<IAssetManaged> assets = dataServerAssetManager.FindAll(typeof(IAssetManaged));
            foreach (IAssetManaged asset in assets)
            {
                AssetManager.Instance.Add(asset);
            }
        }

        private void infoTabControl_Selecting(object sender, TabControlCancelEventArgs e)
        {
            this.cameraEditorControl1.Camera = this.cameraSwitch;
        }

        //loading volumes files in a batch
        public delegate void UpdateProgressBarDelegate();
        private OpenVolumeFilesBatchProgressWindow progressWindow;
        private void volumeFilesBatchToolStripMenuItem_click(object sender, EventArgs e)
        {
            OpenFileDialog fd = new OpenFileDialog();
            fd.Multiselect = true;
            fd.Filter = "Volume files (*.vol;*.raw)|*.vol;*.raw";
            List<String> filenames = new List<String>();
            if (fd.ShowDialog() == DialogResult.OK)
            {
                OpenVolumeFilesBatch batchDialog = new OpenVolumeFilesBatch();
                batchDialog.SetNumberFiles(fd.FileNames.Length);
                int xDim = 0, yDim = 0, zDim = 0;
                if (batchDialog.ShowDialog() == DialogResult.OK)
                {
                    batchDialog.GetVolumeFilesDimensions(out xDim, out yDim, out zDim);
                }

                if (fd.FileNames.Length > 3)
                {
                    progressWindow = new OpenVolumeFilesBatchProgressWindow();
                    progressWindow.SetNumberFiles(fd.FileNames.Length);
                    progressWindow.Show();
                }

                for (int i = 0; i < fd.FileNames.Length; i++)
                {
                    String name = Path.GetFileName(fd.FileNames[i]);
                    TexelFormat type = new TexelFormat();
                    if (batchDialog.GetVolumeDataType().Equals("BYTE"))
                        type.Type = ByteFormat.BYTE;
                    else if (batchDialog.GetVolumeDataType().Equals("SHORT"))
                        type.Type = ByteFormat.SHORT;
                    else if (batchDialog.GetVolumeDataType().Equals("FLOAT"))
                        type.Type = ByteFormat.FLOAT;
                    else if (batchDialog.GetVolumeDataType().Equals("INT"))
                        type.Type = ByteFormat.INT;
                    type.Format = OhioState.Graphics.ImageFormat.ALPHA;
                    Volume vol = (Volume)new Volume(name, xDim, yDim, zDim, type);
                    if (AssetManager.Instance.Find(typeof(Volume), name) == null)
                        AssetManager.Instance.Add((Volume)vol);

                    if (progressWindow != null)
                    {
                        //System.Threading.Thread.Sleep(1000); 
                        //progressWindow.BeginInvoke(new UpdateProgressBarDelegate(updateProgressBarDelegateImpl));
                        //hack! updating UI from a current thread
                        progressWindow.UpdateProgressBar();
                    }
                }
                if (progressWindow != null)
                {
                    progressWindow.Hide();
                    progressWindow.Dispose();
                }
            }
        }

        private void updateProgressBarDelegateImpl()
        {
            if (progressWindow != null) progressWindow.UpdateProgressBar();
            //Console.WriteLine("loading next file...");
        }

        private void generateNoiseTexture_menuItemClick(object sender, EventArgs e)
        {
            GenerateNoiseTextureForm generateTextureDialog = new GenerateNoiseTextureForm();
            if (generateTextureDialog.ShowDialog() == DialogResult.OK)
            {
                String textureName = generateTextureDialog.GetTextureName();
                int x = 0, y = 0, z = 0;
                generateTextureDialog.GetTextureDimensions(out x, out y, out z);

                if (!generateTextureDialog.IsTwoDimensional())
                {
                    //generate 50% noise
                    //assume 3D
                    Texture3D texture3D = new Texture3D(x, y, z);
                    byte[] texData = new byte[x * y * z * 4];
                    Random rand = new Random();
                    for (int i = 0; i < x; i++)
                    {
                        for (int j = 0; j < y; j++)
                        {
                            for (int k = 0; k < z; k++)
                            {
                                byte value = 0;
                                if (rand.Next(10) < 5) value = 255;

                                int index = i * 4 + j * x * 4 + k * x * y * 4;
                                texData[index] = value;
                                texData[index + 1] = value;
                                texData[index + 2] = value;
                                texData[index + 3] = 255;//alpha
                            }
                        }
                    }
                    TexelFormat type = new TexelFormat();
                    type.Type = ByteFormat.BYTE;
                    type.Format = OhioState.Graphics.ImageFormat.ALPHA;
                    Volume volume = new Volume(generateTextureDialog.GetTextureName(), x, y, z, type);
                    volume.ByteData = texData;
                    volume.setDimensions(x, y, z);
                    AssetManager.Instance.Add(volume);
                }
                else //2D
                {
                    byte[] texData = new byte[x * y * 4];
                    Random rand = new Random();
                    for (int i = 0; i < x; i++)
                    {
                        for (int j = 0; j < y; j++)
                        {
                            byte value = 0;
                            if (rand.Next(10) < 5) value = 255;

                            int index = i * 4 + j * x * 4;
                            texData[index] = value;
                            texData[index + 1] = value;
                            texData[index + 2] = value;
                            texData[index + 3] = 255;//alpha
                        }
                    }
                    TexImage texImage = new TexImage(generateTextureDialog.GetTextureName(), texData, x, y);
                    AssetManager.Instance.Add(texImage);
                }
            }
        }

        private void calculateVectorFieldHistogram_itemClick(object sender, EventArgs e)
        {
            VectorFieldHistogramForm vfhForm = new VectorFieldHistogramForm();
            //vfhForm.mo
            vfhForm.Show();
            //if (vfhForm.ShowDialog() == DialogResult.OK)
            //{
            //    //do smth
            //}
        }

        //temp stub
        private void processVectorField_menuItemClick(object sender, EventArgs e)
        {
        }

        ////debug
        //private void processVectorField_menuItemClick(object sender, EventArgs e)
        //{
        //    //1. read in vect.dat
        //    float[,] vX = new float[256, 256];
        //    float[,] vY = new float[256, 256];

        //    FileStream fileStream = new FileStream("C:\\Documents and Settings\\Oleg Mischenko\\Desktop\\vect.dat", FileMode.Open, FileAccess.Read);
        //    StreamReader streamReader = new StreamReader(fileStream);

        //    streamReader.ReadLine();//V2
        //    String sizes = streamReader.ReadLine();//256 256
        //    int vectFieldWidth = int.Parse(sizes.Split(new char[] { ' ' })[0]);
        //    int vectFieldHeight = int.Parse(sizes.Split(new char[] { ' ' })[1]);

        //    String line = "";

        //    String[] separator = new String[] { " " };
        //    for (int i = 0; i < vectFieldWidth; i++)
        //    {
        //        for (int j = 0; j < vectFieldHeight; j++)
        //        {
        //            line = streamReader.ReadLine();
        //            String[] res = line.Split(separator, StringSplitOptions.None);
        //            vX[i, j] = Convert.ToSingle(res[0]);
        //            vY[i, j] = Convert.ToSingle(res[1]);
        //        }
        //    }

        //    streamReader.Close();
        //    fileStream.Close();
        //    //keep flow data as array of columns, where each column is a List
        //    //this allows easy addition/removal of elements with any index
        //    List<float> [] vectorDataX = new List<float>[256];//256 columns
        //    List<float>[] vectorDataY = new List<float>[256];//256 columns
        //    for (int i = 0; i < 256; i++)//init
        //    {
        //        vectorDataX[i] = new List<float>();
        //        vectorDataY[i] = new List<float>();
        //    }
        //    for (int i = 0; i < vectFieldWidth; i++)
        //    {
        //        for (int j = 0; j < vectFieldHeight; j++)
        //        {
        //            //vectorDataX[i].Add(vX[j, i]);
        //            //vectorDataY[i].Add(vY[j, i]);
        //            //should it be i?
                    
        //            vectorDataX[i].Add(vX[i, j]);
        //            vectorDataY[i].Add(vY[i, j]);
        //        }
        //    }

        //    System.Drawing.Bitmap divBitmap = new System.Drawing.Bitmap("C:\\Documents and Settings\\Oleg Mischenko\\Desktop\\testing.png");//vect_div_256.png");//testing.png");
        //    //divBitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);//?
        //    System.Drawing.Bitmap resultBitmap = CreateMinSeam(divBitmap, vectorDataX, vectorDataY, true);
        //    resultBitmap = CreateMaxSeam(resultBitmap, vectorDataX, vectorDataY, true);
        //    for (int i = 0; i < 40; i++)
        //    {
        //        resultBitmap = CreateMinSeam(resultBitmap, vectorDataX, vectorDataY, true);
        //        resultBitmap = CreateMaxSeam(resultBitmap, vectorDataX, vectorDataY, true);
        //    }
        //    resultBitmap.Save("result_bitmap.png", System.Drawing.Imaging.ImageFormat.Png);
            
        //    //save data to a new flow file
        //    FileStream filestream = new FileStream("C:\\Documents and Settings\\Oleg Mischenko\\Desktop\\vect_warp.dat", FileMode.OpenOrCreate);
        //    StreamWriter streamwriter = new StreamWriter(filestream);
        //    streamwriter.WriteLine("V2");
        //    streamwriter.WriteLine("256 256");
        //    for (int i = 0; i < 256; i++)//rows
        //    {
        //        for (int j = 0; j < 256; j++)//columns
        //        {
        //            //data is written out in columns

        //            //if (j < 128)
        //            //{
        //            //    vectorDataX[i][j] = 0.0f;
        //            //    vectorDataY[i][j] = 0.0f;
        //            //}
                    
        //            //streamwriter.WriteLine(vectorDataX[i][j] + " " + vectorDataY[i][j]);
        //            //swap x and y?
        //            streamwriter.WriteLine(vectorDataX[i][j] + " " + vectorDataY[i][j]);
        //        }
        //    }
        //    streamwriter.Close();
        //    filestream.Close();
        //}

        //private System.Drawing.Bitmap CreateMinSeam(System.Drawing.Bitmap divBitmap, List<float>[] vectorDataX, List<float>[] vectorDataY, bool minimize)
        //{
        //    System.Drawing.Bitmap resultBitmap = new System.Drawing.Bitmap(divBitmap);//"C:\\Documents and Settings\\Oleg Mischenko\\Desktop\\vect_div_256.png");//testing.png");
        //    System.Drawing.Bitmap smallerBitmap = new System.Drawing.Bitmap(divBitmap.Width, divBitmap.Height - 1);
        //    //implement seam carving
        //    //work with only horizontal seams for now
        //    //M[i, j] denotes minimal cost of a horizontal seam, coming through [i, j])
        //    //please notice that i here is a row, and j here is a column
        //    //init
        //    float[,] M = new float[divBitmap.Height, divBitmap.Width];
        //    for (int i = 0; i < divBitmap.Height; i++)
        //    {
        //        M[i, 0] = divBitmap.GetPixel(0, i).R;//costs for the first column
        //    }
        //    for (int i = 0; i < divBitmap.Width; i++)//fill first and last row with high values
        //    {
        //        M[0, i] = 1000000;
        //        M[divBitmap.Height - 1, i] = 1000000;
        //    }

        //    for (int i = 1; i < divBitmap.Height - 1; i++)//rows
        //    {
        //        for (int j = 1; j < divBitmap.Height; j++)//columns
        //        {
        //            float a = M[i + 1, j - 1];
        //            float b = M[i, j - 1];
        //            float c = M[i - 1, j - 1];
        //            float min = a;
        //            if (b < a) min = b;
        //            if (c < min) min = c;
        //            byte cR = divBitmap.GetPixel(j, i).R;

        //            M[i, j] = min + cR;
        //        }
        //    }

        //    //starting from left-most (largest) column, find smallest element and then backtrack
        //    //find min in the last column
        //    float minValue = 1000000;
        //    int minIndex = -1;
        //    List<int> indicesDel = new List<int>();
        //    for (int i = 1; i < divBitmap.Height - 1; i++)//don't include 0'th and last rows
        //    {
        //        if (minValue > M[i, divBitmap.Width - 1])//i-th row, 255-th column
        //        {
        //            minValue = M[i, divBitmap.Width - 1];
        //            minIndex = i;//row with the min element
        //        }
        //    }
        //    resultBitmap.SetPixel(divBitmap.Width - 1, minIndex, System.Drawing.Color.Blue);
        //    indicesDel.Add(minIndex);

        //    for (int j = divBitmap.Width - 2 /*254*/; j > 0; j--)//columns, don't include the last one
        //    {
        //        float a = M[minIndex + 1, j - 1];
        //        float b = M[minIndex, j - 1];
        //        float c = M[minIndex - 1, j - 1];

        //        float minV = a;
        //        if (b < a) minV = b;
        //        if (c < minV) minV = c;

        //        if (minV == a) minIndex = minIndex + 1;
        //        //else if (minV == b) minIndex = minIndex;//do nothing
        //        else if (minV == c) minIndex = minIndex - 1;

        //        resultBitmap.SetPixel(j, minIndex, System.Drawing.Color.Blue);
        //        indicesDel.Insert(0, minIndex);
        //    }
        //    //testing that indicesDel contain correct values
        //    int currentX = 0;
        //    foreach (int v in indicesDel)
        //    {
        //        resultBitmap.SetPixel(currentX + 1, v, System.Drawing.Color.Red);
        //        currentX++;
        //    }
        //    if (!minimize)
        //    {
        //        return resultBitmap;
        //    }

        //    for (int i = 1; i < divBitmap.Width; i++)
        //    {
        //        int currentY = 0;
        //        for (int j = 0; j < divBitmap.Height; j++)
        //        {
        //            if (indicesDel[i - 1] == j) continue;
        //            smallerBitmap.SetPixel(i, currentY, divBitmap.GetPixel(i, j));
        //            currentY++;
        //        }
        //    }
        //    //remove data from vectorDataX and vectorDataY
        //    //what to do with the first column? - remove the same as element at column 1
        //    vectorDataX[0].RemoveAt(indicesDel[0]);
        //    vectorDataY[0].RemoveAt(indicesDel[0]);
        //    for (int i = 1; i < divBitmap.Width; i++)
        //    {
        //        //column i
        //        vectorDataX[i].RemoveAt(indicesDel[i - 1]);
        //        vectorDataY[i].RemoveAt(indicesDel[i - 1]);
        //    }

        //    return smallerBitmap;
        //}

        //private System.Drawing.Bitmap CreateMaxSeam(System.Drawing.Bitmap divBitmap, List<float>[] vectorDataX, List<float>[] vectorDataY, bool maximize)
        //{
        //    System.Drawing.Bitmap resultBitmap = new System.Drawing.Bitmap(divBitmap);
        //    System.Drawing.Bitmap largerBitmap = new System.Drawing.Bitmap(divBitmap.Width, divBitmap.Height + 1);
        //    //implement seam carving
        //    //work with only horizontal seams for now
        //    //M[i, j] denotes minimal cost of a horizontal seam, coming through [i, j])
        //    //please notice that i here is a row, and j here is a column
        //    //init
        //    float[,] M = new float[divBitmap.Height, divBitmap.Width];
        //    for (int i = 0; i < divBitmap.Height; i++)
        //    {
        //        M[i, 0] = divBitmap.GetPixel(0, i).R;//costs for the first column
        //    }
        //    for (int i = 0; i < divBitmap.Width; i++)//fill first and last row with low values
        //    {
        //        M[0, i] = -10000000;
        //        M[divBitmap.Height - 1, i] = -10000000;
        //    }

        //    for (int i = 1; i < divBitmap.Height - 1; i++)//rows
        //    {
        //        for (int j = 1; j < divBitmap.Height; j++)//columns
        //        {
        //            float a = M[i + 1, j - 1];
        //            float b = M[i, j - 1];
        //            float c = M[i - 1, j - 1];
        //            float max = a;
        //            if (b > a) max = b;
        //            if (c > max) max = c;
        //            byte cR = divBitmap.GetPixel(j, i).R;

        //            M[i, j] = max + cR;
        //        }
        //    }

        //    //starting from left-most (largest) column, find smallest element and then backtrack
        //    //find min in the last column
        //    float maxValue = 0;
        //    int maxIndex = 1;//don't keep at -1
        //    List<int> indicesAdd = new List<int>();
        //    for (int i = 1; i < divBitmap.Height - 1; i++)//don't include 0'th and last rows
        //    {
        //        if (maxValue < M[i, divBitmap.Width - 1])//i-th row, 255-th column
        //        {
        //            maxValue = M[i, divBitmap.Width - 1];
        //            maxIndex = i;//row with the min element
        //        }
        //    }
        //    //make sure maxIndex is set
        //    resultBitmap.SetPixel(divBitmap.Width - 1, maxIndex, System.Drawing.Color.Blue);
        //    indicesAdd.Add(maxIndex);

        //    for (int j = divBitmap.Width - 2 /*254*/; j > 0; j--)//columns, don't include the last one
        //    {
        //        float a = M[maxIndex + 1, j - 1];
        //        float b = M[maxIndex, j - 1];
        //        float c = M[maxIndex - 1, j - 1];

        //        float maxV = a;
        //        if (b > a) maxV = b;
        //        if (c > maxV) maxV = c;

        //        if (maxV == a) maxIndex = maxIndex + 1;
        //        //else if (maxV == b) maxIndex = maxIndex;//do nothing
        //        else if (maxV == c) maxIndex = maxIndex - 1;

        //        resultBitmap.SetPixel(j, maxIndex, System.Drawing.Color.Magenta);
        //        indicesAdd.Insert(0, maxIndex);
        //    }
        //    //testing that indicesDel contain correct values
        //    int currentX = 0;
        //    foreach (int v in indicesAdd)
        //    {
        //        resultBitmap.SetPixel(currentX + 1, v, System.Drawing.Color.Magenta);
        //        currentX++;
        //    }
        //    if (!maximize)
        //    {
        //        return resultBitmap;
        //    }

        //    for (int i = 1; i < divBitmap.Width; i++)
        //    {
        //        bool pixelSet = false;
        //        for (int j = 0; j < divBitmap.Height + 1; j++)
        //        {
        //            if (indicesAdd[i - 1] == j)
        //            {
        //                largerBitmap.SetPixel(i, j, System.Drawing.Color.WhiteSmoke);//todo: make color mix of surrounding colors
        //                if (i - 1 >= 0 && i + 1 < divBitmap.Width && j - 1 >= 0 && j + 1 < divBitmap.Height - 1)
        //                {
        //                    int newColor = 0;
        //                    newColor = divBitmap.GetPixel(i - 1, j).R + divBitmap.GetPixel(i + 1, j).R +
        //                        divBitmap.GetPixel(i, j - 1).R + divBitmap.GetPixel(i, j + 1).R;
        //                    newColor /= 4;
        //                    largerBitmap.SetPixel(i, j, System.Drawing.Color.FromArgb(newColor, newColor, newColor));
        //                }
        //                pixelSet = true;
        //                continue;
        //            }
        //            if(pixelSet)
        //                largerBitmap.SetPixel(i, j, divBitmap.GetPixel(i, j - 1));
        //            else
        //                largerBitmap.SetPixel(i, j, divBitmap.GetPixel(i, j));
        //        }
        //    }

        //    //remove data from vectorDataX and vectorDataY
        //    //what to do with the first column? - remove the same as element at column 1            
        //    vectorDataX[0].Insert(indicesAdd[0], 1.0f);//change inserted values
        //    vectorDataY[0].Insert(indicesAdd[0], 1.0f);
        //    for (int i = 1; i < divBitmap.Width; i++)
        //    {
        //        //column i
        //        int h = indicesAdd[i - 1];
                
        //        //new values are averages over neighboring locations
        //        float newValueX = 1.0f;
        //        if(h + 1 < divBitmap.Height && h - 1 >= 0 && i + 1 < divBitmap.Width)
        //            newValueX = (vectorDataX[i - 1][h] + vectorDataX[i + 1][h] + vectorDataX[i][h - 1] + vectorDataX[i][h + 1])*0.25f;
        //        float newValueY = 1.0f;
        //        if (h + 1 < divBitmap.Height && h - 1 >= 0 && i + 1 < divBitmap.Width)
        //            newValueY = (vectorDataY[i - 1][h] + vectorDataY[i + 1][h] + vectorDataY[i][h - 1] + vectorDataY[i][h + 1]) * 0.25f;

        //        vectorDataX[i].Insert(h, newValueX);
        //        vectorDataY[i].Insert(h, newValueY);
        //    }

        //    return largerBitmap;
        //}
    }
}